﻿
using Dapper;

using HBase;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Reflection.Emit;
using System.Reflection.Metadata;
using System.Transactions;

namespace hCommand {
    /**
   *┌────────────────────────────────────────────────┐
   *│　描    述：Component                                                    
   *│　作    者：sgj                                              
   *│　版    本：1.0                                              
   *│　创建时间：2020/9/2 11:28:16                        
   *└────────────────────────────────────────────────┘
   **/
    public abstract class AbsLocEngine : ChangeLocComp {
        private const int MAX_WEIGHT = 100000000;

        public  CoreWhLoc selectLoc<CS>(IDbConnection connection, IDbTransaction transaction, CS cs) where CS : AbsCoreStock {
          
            long itemClassifyId = cs.classifyId;
            if (itemClassifyId == 0) {
                throw new Exception(cs.id + "的分类未找到");
            }
            long goodDiff = cs.deepDiff;
            CoreWhLoc beforeLoc = locBeforeSelect(itemClassifyId, goodDiff);
            if (beforeLoc != null) {
                return beforeLoc;
            }
            //一个物料类别对应多个区域
            CoreWhLoc loc = getBastCoreWhLoc( connection, transaction, cs);
            return loc;
        }


        public virtual CoreWhLoc getBastCoreWhLoc<CS>(  IDbConnection conn, IDbTransaction trans, CS cs) where CS : AbsCoreStock {
           
            AreaLocWeightDto dto = null;
            string sql = @"select * from core_classify_Area  where classify_Id=@classifyId and eigen=@eigen order by Priority ";
            //一个物料类别对应多个区域 查询物料优先放在哪个区域
            List<CoreClassifyArea> coreClassifyAreaList = conn.Query<CoreClassifyArea>(sql, cs, trans).ToList();

            for (int j = 0; j < coreClassifyAreaList.Count; j++) {
                CoreClassifyArea areaDto = coreClassifyAreaList[j];
                List<CoreWhLoc> locList = getLoc4SelectIn(areaDto.areaId, -1, conn, trans);
                if (locList.Count == 0) {
                    CoreWhArea area = conn.GetById<CoreWhArea>(areaDto.areaId, trans);
                    if (area != null) {
                        LoggerCommon.consol(InfoCode.consle_loc_full, areaDto.id+ area.AreaName + "无可用货位");

                    } else {
                        LoggerCommon.consol(InfoCode.consle_loc_full, areaDto.areaId + "无可用货位");

                    }
                    continue;
                }

                AreaLocWeightDto tmp = getAreaLocWeightDto(areaDto.priority, locList, cs);
                tmp = locChangeWeight(cs.classifyId, cs.deepDiff, tmp);
                if (tmp == null) {
                    continue;
                }
                if (tmp.weight == MAX_WEIGHT && tmp.loc != null) {//起到优化作用，减少无意义循环
                    return tmp.loc;
                }
                if (dto == null || tmp.weight > dto.weight) {
                    dto = tmp;
                }
            }
            if (dto == null || dto.loc == null) {
                return null;
            }

            return locFinally(dto);
        }
        protected virtual CoreWhLoc locBeforeSelect(long itemClassifyId, long group) {
            return null;
        }
        protected virtual CoreWhLoc locFinally(AreaLocWeightDto dto) {
            return dto.loc;
        }
        protected virtual AreaLocWeightDto locChangeWeight(long itemClassifyId, long group, AreaLocWeightDto tmp) {
            return tmp;
        }
        protected virtual bool checkLast(List<CoreWhLoc> locList) {
            int count = 0;
            int relse = 0;
            foreach (CoreWhLoc loc in locList) {
                if (loc.type != 1) {
                    count++;
                }
                if (loc.countStock < loc.maxStock) {
                    relse++;
                }
            }
            return count > 0 && relse <= 1;
        }
        protected virtual AreaLocWeightDto getAreaLocWeightDto<CS>( int priority, List<CoreWhLoc> alllocList, CS cs) where CS : AbsCoreStock {
            Dictionary<long, List<CoreWhLoc>> coreWhLocDict = groupLoc(alllocList);
            long goodDiff = cs.deepDiff;
            AreaLocWeightDto max = null;
            foreach (var item in coreWhLocDict) {
                List<CoreWhLoc> locList = item.Value;
                if (checkLast(locList)) {
                    continue;
                }

                AreaLocWeightDto areaLocWeightDto = new AreaLocWeightDto();
                if (priority == 1) {
                    areaLocWeightDto.weight = MAX_WEIGHT;
                    CoreWhLoc loc = AllocateLoc(locList, goodDiff, cs);
                    areaLocWeightDto.loc = loc;
                    if (loc != null) {
                        return areaLocWeightDto;
                    }
                } else if (priority == 2) {
                    areaLocWeightDto.weight = locList.Count();
                    areaLocWeightDto.loc = AllocateLoc(locList, goodDiff, cs);
                } else if (priority == 3) {
                    float count = 0;
                    foreach (CoreWhLoc loc in locList) {
                        count += loc.countStock;
                    }
                    areaLocWeightDto.weight = (int)((1 - count / locList.Count()) * MAX_WEIGHT);
                    areaLocWeightDto.loc = AllocateLoc(locList, goodDiff, cs);
                }
                if (areaLocWeightDto.loc == null) {
                    continue;
                }
                if (max == null) {
                    max = areaLocWeightDto;
                } else if (areaLocWeightDto.weight > max.weight) {
                    max = areaLocWeightDto;
                }
            }
            return max;
        }
        protected virtual CoreWhLoc AllocateLoc<CS>(List<CoreWhLoc> locList, long goodDiff, CS cs) where CS : AbsCoreStock {
           
            CoreWhLoc loc = I18nConfig.select(locList, goodDiff, cs);
            return afterSelect(loc, locList, goodDiff);
        }

        protected virtual CoreWhLoc afterSelect(CoreWhLoc loc, List<CoreWhLoc> locList, long goodDiff) {
            return loc;
        }
        protected  Dictionary<long, List<CoreWhLoc>> groupLoc(List<CoreWhLoc> locList) {
            Dictionary<long, List<CoreWhLoc>> coreWhLocDict = new Dictionary<long, List<CoreWhLoc>>();
            foreach (CoreWhLoc coreWhLoc in locList) {
                if (coreWhLocDict.ContainsKey(coreWhLoc.moveGroup)) {
                    coreWhLocDict[coreWhLoc.moveGroup].Add(coreWhLoc);
                } else {
                    coreWhLocDict.Add(coreWhLoc.moveGroup, new List<CoreWhLoc>() { coreWhLoc });
                }
            }
            return coreWhLocDict;
        }

        
        

      virtual   public   List<CoreWhLoc> getLoc4SelectIn(long areaId, long moveGroup, IDbConnection conn, IDbTransaction tran) {
            string sql = null;
            if (BaseConfig.islocGroup) {
                sql = "select l.* from Core_Wh_Loc l join core_wh_group g on  g.area_id=l.area_id and g.loc_group=l.move_group  where  l.Active_Status in (0,2) and  wcs_Auto_active =1 ";

            } else {
                sql = "select l.* from Core_Wh_Loc l where  l.Active_Status in (0,2) ";
            }
            if (areaId != -1) {
                sql += " and   l.area_Id = @areaId  ";
            }
            if (moveGroup != -1) {
                sql += " and   l.move_Group=@moveGroup  ";
            }
            sql += i18nSql();
            sql += "order by order_No";
           // LoggerCommon.consoleOnly(10, sql);
            List<CoreWhLoc> locList = conn.Query<CoreWhLoc>(sql, new { areaId, moveGroup }, tran).ToList();
            return locList;
        }

        public virtual String i18nSql() {
            return "";
        }
    }
}

